/*=+--+=#=+--     Unmanned Aerial System Management Software      --+=#=+--+=#*\
|          Copyright (C) 2011 Regents of the University of Colorado.           |
|                             All Rights Reserved.                             |

     This program is free software: you can redistribute it and/or modify
     it under the terms of the GNU General Public License version 2 as
     published by the Free Software Foundation.

     This program is distributed in the hope that it will be useful,
     but WITHOUT ANY WARRANTY; without even the implied warranty of
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     GNU General Public License for more details.

     You should have received a copy of the GNU General Public License
     along with this program.  If not, see <http://www.gnu.org/licenses/>.

            Jack Elston                       Cory Dixon                        
|           elstonj@colorado.edu              dixonc@colorado.edu              |
|                                                                              |
\*=+--+=#=+--                 --+=#=+--+=#=+--                    --+=#=+--+=#*/

/***********************************************************************
 *
 * FILENAME:
 * String.cxx
 *
 * PURPOSE:
 * Implements a C++ string class, and does most
 * of the operations one might expect a good string
 * class to do.
 *
 * CREATED:
 * 11/2000 by Cory Dixon
 *
 * LAST MODIFIED:
 * $Author: dixonc $
 * $Date: 2005/07/13 21:00:06 $
 * $Revision: 1.2 $
 *
 ***********************************************************************/

// includes
#include "String.h"
#include "type_defs.h"

////////////////////////////////////////////////////////////////////////////////
// Public methods


////////////////////////////////////////////////////////////////////////////////
//
// String::String - construct a String from a C-string
//
// This constructor constructs a String object from a NULL terminated C-string.
//
// RETURNS:  N/A
//
#include <stdio.h>
String::String (const char * s)
{
	if( s == NULL ) {
		len = 0;
		str = new char[1];
		str[0] = '\0';
	} else {
		len = strlen (s);
		str = new char[len + 1];
		strcpy (str, s);
	}
	//printf("String:String - %s\n", str);
}

////////////////////////////////////////////////////////////////////////////////
//
// String::String - default constructor
//
// The default constructor for String will construct a String object which
// is initially empty.
//
// RETURNS:  N/A
//
String::String ()
{
	len = 0;
	str = new char[1];
	str[0] = '\0';
}
////////////////////////////////////////////////////////////////////////////////
//
// String::String - copy constructor
//
// The copy constructor for String will construct a String object from
// another String object.
//
// RETURNS:  N/A
//
String::String (const String & st)
{
	len = st.len;
	//printf("String:String - length=%i\n",len);
	str = new char[len + 1];
	//printf("String:String - %s\n", st.str);
	strcpy (str, st.str);
}

////////////////////////////////////////////////////////////////////////////////
//
// String::~String - String destructor
//
// The string destructor, when invoked, will delete memory allocated for
// strings.
//
// RETURNS:  N/A
//
String::~String ()
{
	if( str != NULL )
		delete [] str;
	str = NULL;
}
////////////////////////////////////////////////////////////////////////////////
//
// String::tolower
//  make string lowercase
//
// RETURNS:  na
//
void String::tolower()
{
	for(size_t i=0; i<len && str[i]; i++){
		str[i] = ::tolower(str[i]);
	}
}

void String::toupper()
{
	for(size_t i=0; i<len && str[i]; i++){
		str[i] = ::toupper(str[i]);
	}
}

int String::find(const String & st)
{
	char *found = strstr(str, st.str);
	if(found) {
		return (found - str);
	} else
		return -1;
}

int String::find(const char *s)
{
	char *found = ::strstr(str, s);
	if(found) {
		return (found - str);
	} else
		return -1;
}

////////////////////////////////////////////////////////////////////////////////
//
// String::operator= - assign a String to a String
//
// This assignment operator will assign one String object to another String
// object.
//
// RETURNS:  A reference to the invoking object ( *this ).
//
String & String::operator=(const String & st)
{
	if ( this == &st )
		return *this;

	if( str != NULL )
		delete [] str;
	str = NULL;

	len = st.len;
	str = new char[len + 1];
	strcpy (str, st.str);

	return *this;
}

////////////////////////////////////////////////////////////////////////////////
//
// String::operator= - assign a C string to a String object
//
// This assignment operator will assign a C string to a String object.
//
// RETURNS:  A reference to the invoking object ( *this ).
//
String & String::operator=(const char * s)
{
	delete [] str;
	str = NULL;

	if( s == NULL ) {
		len = 0;
		str = new char[1];
		str[0] = '\0';
	} else {
		len = strlen (s);
		str = new char[len + 1];
		strcpy (str, s);
	}	

	return *this;
}

////////////////////////////////////////////////////////////////////////////////
//
// String::operator+= - append a String to a String
//
// This operator will append a String object to a String object.  Given two
// String objects:
//
// String obj1 = "Hello, ";
// String obj2 = "World!";
//
// obj1 += obj2;
//
// will result in the string, "Hello, World!", being stored in obj1. 
//
// RETURNS:  A reference to the invoking object.
//
String & String::operator+=(const String & st)
{
	char * tempString = new char[len + st.len + 1];

	strcpy (tempString, str);
	strcpy ((tempString + len), st.str);

	// get rid of the old string
	delete [] str;
	str = NULL;
	len = strlen (tempString);
	str = new char[len + 1];


	// copy the temp string to this string, and get rid of the temp string
	strcpy (str, tempString);
	delete [] tempString;

	return *this;
}

////////////////////////////////////////////////////////////////////////////////
//
// String::operator+= - append a C string to a String
//
// This operator will append a C strintg to a String object.  Given a C string 
// and a String object:
//
// String obj1 = "Hello, ";
// char * obj2 = "World!";
//
// obj1 += obj2;
//
// will result in the string, "Hello, World!", being stored in obj1. 
//
// RETURNS:  A reference to the invoking object.
//

String & String::operator+=(const char * s)
{

	if( s == NULL )
		return *this;

	char * tempString = new char[len + strlen(s) + 1];

	strcpy (tempString, str);
	strcpy ((tempString + len), s);

	// get rid of the old string
	delete [] str;
	str = NULL;

	len = strlen (tempString);
	str = new char[len + 1];

	// copy the temp string to this string, and get rid of the temp string
	strcpy (str, tempString);
	delete [] tempString;

	return *this;
}


////////////////////////////////////////////////////////////////////////////////
// Friends


////////////////////////////////////////////////////////////////////////////////
//
// operator> - compare two String objects
//
// This operator, a friend method, compares two String objects.
//
// RETURNS:
//	TRUE, if st1 is greater than (follows) st2 in the machine sort order.
//	FALSE, if st1 is not greater than st2 in the machine sort order.
//
bool operator>(const String & st1, const String & st2)
{
	if ( strcmp (st1.str, st2.str) > 0 )
		return TRUE;
	else
		return FALSE;
}

////////////////////////////////////////////////////////////////////////////////
//
// operator< - compare two String objects
//
// This operator, a friend method, compares two String objects.
//
// RETURNS:
//	TRUE, if st1 is less than (precedes) st2 in the machine sort order.
//	FALSE, if st1 is not less than st2 in the machine sort order.
//
bool operator<(const String & st1, const String & st2)
{
	if ( strcmp (st1.str, st2.str) < 0 )
		return TRUE;
	else
		return FALSE;
}

////////////////////////////////////////////////////////////////////////////////
//
// operator== - compare two String objects
//
// This operator, a friend method, compares two String objects.
//
// RETURNS:
//	TRUE, if st1 and st2 are identicle in the machine sort order.
//	FALSE, if st1 and st2 are not identicle in the machine sort order.
//
bool operator==(const String & st1, const String & st2)
{
	if( st1.str == NULL || st2.str == NULL )
		return FALSE;
	if ( strcmp (st1.str, st2.str) == 0 )
		return TRUE;
	else
		return FALSE;
}

////////////////////////////////////////////////////////////////////////////////
//
// operator== - compare a String object with a char *
//
// This operator, a friend method, compares a String object with a char *
//
// RETURNS:
//	TRUE, if st1 and st2 are identicle in the machine sort order.
//	FALSE, if st1 and st2 are not identicle in the machine sort order.
//
bool operator==(const String & st1, const char * st2)
{
	if(st2 == NULL || st1.str == NULL)
		return FALSE;
	if ( strcmp (st1.str, st2) == 0 )
		return TRUE;
	else
		return FALSE;
}
bool operator==(const char * st1, const String & st2)
{
	if( st1 == NULL || st2.str == NULL )
		return FALSE;
	if ( strcmp (st1, st2.str) == 0 )
		return TRUE;
	else
		return FALSE;
}

////////////////////////////////////////////////////////////////////////////////
//
// operator!= - compare two String objects
//
// This operator, a friend method, compares two String objects.
//
// RETURNS:
//	FALSE, if st1 and st2 are identicle in the machine sort order.
//	TRUE, if st1 and st2 are not identicle in the machine sort order.
//
bool operator!=(const String & st1, const String & st2)
{
	if ( st1.str == NULL || st2.str == NULL )
		return FALSE;
	if ( strcmp (st1.str, st2.str) == 0 )
		return FALSE;
	else
		return TRUE;
}

////////////////////////////////////////////////////////////////////////////////
//
// operator!= - compare a String object with a char *
//
// This operator, a friend method, compares a String object with a char *
//
// RETURNS:
//	FALSE, if st1 and st2 are identicle in the machine sort order.
//	TRUE, if st1 and st2 are not identicle in the machine sort order.
//
bool operator!=(const String & st1, const char * st2)
{
	if(st2 == NULL || st1.str == NULL)
		return false;
	if ( strcmp (st1.str, st2) == 0 )
		return FALSE;
	else
		return TRUE;
}
bool operator!=(const char * st1, const String & st2)
{
	if(st1 == NULL || st2.str == NULL)
		return false;
	if ( strcmp (st1, st2.str) == 0 )
		return FALSE;
	else
		return TRUE;
}

////////////////////////////////////////////////////////////////////////////////
//
// operator<< - write a String object to the standard ostream object
//
// This operator, a friend method, inserts a String into an ostream object.
//
// RETURNS:  A reference to an ostream object.
//
ostream & operator<<(ostream & os, const String & st)
{
	os << st.str;
	return os;
}

////////////////////////////////////////////////////////////////////////////////
//
// operator>> - read a String object from the standard istream object
//
// This operator, a friend method, extracts a String from an istream object.
// This overloaded extraction operator for the String class is somewhat
// limited; it will only read up to STRING_MAX_ISTREAM_BUF characters from the 
// standard input stream.
//
// RETURNS:  A reference to an istream object. 
//
istream & operator>>(istream & is, String & st)
{
	char temp[STRING_MAX_ISTREAM_BUF];

	if ( is.getline (temp, STRING_MAX_ISTREAM_BUF) && temp[0] != '\0' )
		st = temp;

	// If user entered nothing, may have to reset the
	// failbit if compiler impliments draft standard

	if ( cin.fail () )
		cin.clear ();

	return is;
}

String operator + (const String & s1, const String & s2)
{
	String tmp(s1);
	tmp += s2;
	return tmp;
}

String operator  + (const String & s1, const char * s2)
{
	return s1 + String(s2);
}

String operator  + (const char * s1, const String & s2)
{
	return String(s1) + s2;
}
